/*
 * Copyright (c) 2007, Dennis N. Mehay
 * DynamicLexicon.java
 *
 * Created on November 5, 2007, 12:26 PM
 */

package opennlp.ccg.lexicon;

import supertagger.tagger.Supertagger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import opennlp.ccg.grammar.Grammar;
import opennlp.ccg.synsem.Category;
import opennlp.ccg.synsem.LF;
import opennlp.ccg.synsem.Sign;
import opennlp.ccg.synsem.SignHash;
import supertagger.util.MyTokeniser;

/**
 *
 * @author Dennis N. Mehay
 */
public class DynamicLexicon {
    
    private Supertagger tagger;
    private MyTokeniser helper;
    private Lexicon wrappedLexicon;
    
    /** Creates a new instance of DynamicLexicon
     * @param grammar A <tt>opennlp.ccg.grammar.Grammar</tt> object
     * @param tagger A <tt>supertagger.tagger.Supertagger</tt> object for
     *        dynamically controlling the lexical look-ups.
     */
    public DynamicLexicon(Lexicon wrapped, Supertagger tagger) {
        this.wrappedLexicon = wrapped;
        this.tagger = tagger;
        this.helper = tagger.getTokeniser();
    }
    
    
    /**
     * For a string of 1 or more surface words, return all of the lexical
     * entries for each word as a list of sign hashes.
     * Lexical look-up is controlled by the supertagger of this class.
     *
     * @param w the words in string format
     * @return a list of sign hashes
     * @exception LexException thrown if word not found
     */
    public List<SignHash> getEntriesFromWords(String w_pos_pairs) throws LexException {
        // Supertag the <L word_1 POS_1> ... <L word_N POS_N> sequence.
        ArrayList<ArrayList<supertagger.util.Pair<Double,String>>> supertagSets =
                tagger.getMultitagLabels(w_pos_pairs);
        List<String[]> tokenGroups = this.helper.getTokenGroups(w_pos_pairs);
        List<String> wordStrings = new ArrayList<String>(tokenGroups.size()),
                poses = new ArrayList<String>(tokenGroups.size());
        
        String sentence = "";
        // Get the words and POSs.
        for(String[] tg : tokenGroups) {
            wordStrings.add(this.helper.getLexItem(tg));
            sentence += this.helper.getLexItem(tg) + " ";
            poses.add(this.helper.getPOS(tg));
        }
                
        // The result to return...eventually.
        List<SignHash> tempEntries = wrappedLexicon.getEntriesFromWords(sentence);
        
        // Filter out those Signs that the supertagger doesn't like.
        List<supertagger.util.Pair<Double,String>> possibleSTs = null;
        SignHash tempSH = null;
        
        List<SignHash> entries = new ArrayList<SignHash>(tempEntries.size());
        
        ArrayList<Sign> tempRes = null;
        for(int n = 0; n < tempEntries.size(); n++) {            
            possibleSTs = supertagSets.get(n);
            tempSH = tempEntries.get(n);
            tempRes = new ArrayList<Sign>(tempSH.size());
            supertagger.util.Pair tempPR = null;
            String supertagNoIndices = null;
            for(Sign sg : tempSH.asSignSet()) {
                for(Iterator<supertagger.util.Pair<Double,String>> pit = possibleSTs.iterator(); pit.hasNext(); ){
                    tempPR = pit.next();
                    supertagNoIndices = removeIndicesEtc((String)tempPR.b);
                    //System.out.println("st: "+supertagNoIndices + " ?= "+sg.getCategory().getSupertag());
                    if(supertagNoIndices.equals(sg.getCategory().getSupertag())) {
                        System.out.println("added: "+supertagNoIndices);
			//sg.setLogProb(((Double)tempPR.a).doubleValue());
                        tempRes.add(sg);
                    }
                }
            }
            entries.add(new SignHash(tempRes));
        }
        /*
        SignHash shTemp = null;
        // For each multitag set, create a hash of Signs.
        for(int i=0; i<supertagSets.size(); i++) {
            shTemp = new SignHash();
            String wString = wordStrings.get(i),
                   posString = poses.get(i);
            
            
            Word wTmp = null;
            EntriesItem eiTmp = null;
            MorphItem mphTmp = null;
            MacroAdder maTmp = null;
            
            ArrayList<supertagger.util.Pair<Double,String>> multitagSet = supertagSets.get(i);
            Collection<EntriesItem> entriesPossible = _posToAllEntries.get(posString);
            for(supertagger.util.Pair<Double,String> tag : multitagSet) {
                // The log-probability of this supertag.
                double logProb = Math.log(tag.a.doubleValue());
                
                wTmp = Word.createWord(wString, null, null, wString, posString, null, wString);
                
                // Build a MorphItem
                mphTmp = new MorphItem(); 
                mphTmp.setWord(wTmp); mphTmp.setSurfaceWord(wTmp);
                
                // Get a hashed EntriesItem.
                for(EntriesItem ei : entriesPossible) {
                    if(ei.getCat().getSupertag().equalsIgnoreCase(tag.b)) {
                        eiTmp = ei;
                        break;
                    }
                }
                
                // Get a MacAdder.
                maTmp = getMacAdder(mphTmp);
                getWithEntriesItem(wTmp, mphTmp, wTmp.getStem(), wTmp.getSemClass(), eiTmp, maTmp, null, logProb, shTemp);
            }
            entries.add(shTemp);
        }*/
        return entries;
    }
    
    /** Remove indices (_1, _2, etc.) and other things like asterisks, tildes, etc., since
     *  OpenCCG wants to remove them from the supertags it stores. (???!!!!)
     */
    private String removeIndicesEtc(String supertag) {
        String res = "";
        res = supertag;
        res = res.replaceAll("[*]", "");
        res = res.replaceAll("~", "");
        res = res.replaceAll("\\d+", "");        
				res = res.replaceAll("_", "");
        return res;
    }
    /*
    // given EntriesItem (just following suit with the sparse documentation...)
    protected void getWithEntriesItem(Word w, MorphItem mi,
            String stem, String pred,
            EntriesItem item,
            MacroAdder macAdder,
            LF lf,
            double logProb,
            SignHash result) {
        // ensure apropos
        if (!item.getActive().booleanValue()) return;
        if (mi.excluded(item)) return;
        
        try {
            // copy and add macros
            Category cat = item.getCat().copy();
            macAdder.addMacros(cat);
            
            // replace DEFAULT_VAL with pred, after first
            // unifying type of associated nom var(s) with sem class
            unifySemClass(cat, mi.getWord().getSemClass());
            REPLACEMENT = pred;
            cat.deepMap(defaultReplacer);
            
            // propagate types of nom vars
            propagateTypes(cat);
            
            // handle distrib attrs and inherits-from
            propagateDistributiveAttrs(cat);
            expandInheritsFrom(cat);
            
            // merge stem, pos, sem class from morph item, plus supertag from cat
            Word word = Word.createFullWord(w, mi.getWord(), cat.getSupertag());
            Sign tmp = new Sign(word, cat);
            tmp.setLogProb(logProb);
            result.insert(tmp);
        } catch (RuntimeException exc) {
            System.err.println(
                    "Warning: ignoring entry: " + item.getName() + " of family: " + item.getFamilyName() +
                    " for stem: " + stem + " b/c: " + exc.toString()
                    );
        }
    }*/
}
